import ilog.concert.IloException;
import ilog.concert.IloIntVar;
import ilog.concert.IloLinearNumExpr;
import ilog.cplex.IloCplex;

import my_cplex.my_cplex;
//尝试写一下自己的想法代码
public class cplex_4 {
    //第一个参数是代理真实承担的角色数量，第二个参数是代理能够承担角色的最大数量，返回值是一个衰减的值
    public double activation(int realTakeNumber,int abilityNumber){
        return Math.exp(-0.5*(realTakeNumber-1)/abilityNumber);
    }
    public static void main(String args[]) throws IloException {

        IloCplex model = new IloCplex();

        //初始化数据集
        my_cplex my_cplex = new my_cplex();

        int k = 3;//组数
        int rows = 6;//代理数量
        int cols = 4;//角色数量
        int[] realTakeNubmer = new int[rows];//代理i实际承担的角色数量，用于代理单位时间工作量的计算

        //资格矩阵Q，资格矩阵不变，因为每个任务中的角色都是相同的
        System.out.println("资格矩阵：");
//        double[][] Q1 = my_cplex.create_dataset(rows,cols,true,1);
        double[][] Q1 = {{0.52,0.19 ,0.03 ,0.12},
                {0.46 ,0.65 ,0.54 ,0.43},
                {0.03 ,0.64 ,0.38 ,0.08},
                {0.48 ,0.93 ,0.75 ,0.92},
                {0.37 ,0.27 ,0.09 ,0.26},
                {0.52 ,0.07 ,0.31 ,0.08}};
        System.out.println("单位时间的工作量矩阵：");
//        double[][] Q2 = my_cplex.create_dataset(rows,cols,true,7);
        double[][] Q2 = {{0.11 ,4.51 ,4.77 ,1.04},
                {3.01 ,6.2 ,2.24 ,3.8},
                {0.01 ,6.81 ,0.99 ,0.33},
                {4.07 ,0.05 ,5.15 ,3.37},
                {6.17 ,0.23 ,1.64 ,0.22},
                {3.5 ,2.26 ,6.74 ,6.3}};

        //L向量，角色需求向量
        //int[] L= {2,2,2,2,2,2};
        //就是k行，cols列
        int[][] L = {{1,1,1,1},
                {2,2,2,2},
                {1,2,1,2}};

        //La向量，代理能力向量
        int[] La = {5,3,4,2,4,3};

        //每个小组单位时间内的最小工作量
        int[] WL_limit = {10,10,10};

        //敏感性系数，代表不同的代理对自己承担任务数量的敏感度θ[i]，作为
        double[] θ = {0.6,0.2,0.3,0.4,0.5,0.1};

        //决策变量，T矩阵
        IloIntVar[][][] T = new IloIntVar[k][rows][cols];
        for(int h=0;h<k;h++){
            for(int i=0;i<rows;i++){
                for(int j=0;j<cols;j++){
                    T[h][i][j] = model.intVar(0,1,"T["+h+","+i+","+j+"]");
                }
            }
        }

        //定义约束条件
        //T[i,j]∈{0,1}已经隐含到决策变量中了

        //L[k,j]向量的限制，因为L矩阵是一个k×j维的，所以不需要过多修改，比较简单
        for(int h=0;h<k;h++){
            for(int j=0;j<cols;j++){//列求和
                IloLinearNumExpr colSum = model.linearNumExpr();
                for(int i=0;i<rows;i++){
                    //addTerm第一个是系数，第二个是数据项
                    colSum.addTerm(1.0,T[h][i][j]);
                }
                //void addEq(IloNumExpr expr, double value, String name)，线性表达式，常数，约束的名称（可选）
                //这里是大于等于，就是要将所有的代理全部分配完，并使得分配之后的代理完成的质量最高，哪个适合就分配到哪里去，干自己擅长的工作
                model.addGe(colSum,L[h][j]);//这里变成多个组
            }
        }


        //La[i]向量的限制，是所有组分配出去的代理会产生问题，但是La向量还是一维的，约束方式要进行修改，同一行的数据要进行相加，再进行约束
        //因为这里是针对相同行的约束，所以需要五个行约束
        //rowsSums:一个代理承担的总角色数量
        IloLinearNumExpr rowsSums[] = new IloLinearNumExpr[rows];
        //初始化一下
        for(int i=0;i<rows;i++){
            rowsSums[i] = model.linearNumExpr();
        }
        for(int h=0;h<k;h++){
            for(int i=0;i<rows;i++){
                for(int j=0;j<cols;j++){
                    //对数据进行求和
                    rowsSums[i].addTerm(1.0,T[h][i][j]);
                }
            }

        }
        //将代理能力矩阵约束添加到表达式中
        for(int i=0;i<rows;i++){
            model.addLe(rowsSums[i],La[i]);
        }

        //再添加Q2的约束，每次分配时的最小工作量下限
        // 2025年5月8日20:18:00：现在尝试加入代理工作量衰减，暂时还没想出来该怎么添加，T矩阵只有在分配之后才知道，而约束里面又需要使用T矩阵分配后的值
        //2025年5月8日21:06:21：明天尝试一下使用一个新的约束去表达代理实际分配的角色数量R[i],这样去试一下能不能成功，不能的话，这个想法大概是无了
        //2025年5月9日11:09:40：在约束里面添加这个值，会导致反复依赖，且不是一个线性求解表达式，没办法进行求解，这个想法失败
        IloLinearNumExpr WLSums[] = new IloLinearNumExpr[k];
        //初始化y一下
        for(int i=0;i<k;i++){
            WLSums[i] = model.linearNumExpr();
        }
        for(int h=0;h<k;h++){
            for(int i=0;i<rows;i++){
                for(int j=0;j<cols;j++){
//                    //这里要先算出代理实际承担的角色数量
//                    for(int l=0;l<k;l++){
//                        for(int m=0;m<cols;m++){
////                            realTakeNubmer[i] =  realTakeNubmer[i] + T[l][i][m];
//                        }
//                    }
                    //对数据进行求和，addTerm第一个参数是常数，第二个参数是决策变量
                    WLSums[h].addTerm(Q2[i][j],T[h][i][j]);
                }
            }
        }
        //将约束添加到里面去
        for(int i=0;i<k;i++){
            //这里要大于等于小组内的单位时间内的工作量
            model.addGe(WLSums[i],WL_limit[i]);
        }

        //设置目标函数
        IloLinearNumExpr objExpr = model.linearNumExpr();
        for(int h=0;h<k;h++){
            for(int i=0;i<rows;i++){
                for(int j=0;j<cols;j++){
                    //目标函数第一部分
                    objExpr.addTerm(Q1[i][j],T[h][i][j]);
                }
            }
        }
        //想在这里加入目标函数的第二个部分，注意目标函数两个部分的循环内容不同，如果想要放在一个循环中，需要调整
        for(int i=0;i<rows;i++){
            for(int h=0;h<k;h++){
                for(int j=0;j<cols;j++){
                    //这个表示因为代理承担了多个角色后产生的一个效率衰减，这里称为衰减，目前就是这个意思
                    objExpr.addTerm(-θ[i]/La[i],T[h][i][j]);
                    objExpr.setConstant(θ[i]/La[i]);
                }
            }
        }
        model.addMaximize(objExpr);

        if(model.solve()){
            model.output().println("Solution status = " + model.getStatus());
            model.output().println("Solution value = " + model.getObjValue());
            for(int h=0;h<k;h++){
                for (int i = 0; i < rows; i++) {
                    for (int j = 0; j < cols; j++) {
                        //System.out.println("x[" + i + "," + j + "]: " + model.getValue(x[i][j]));
                        //避免输出-0.0数据，加上0.0可以避免
                        double value = model.getValue(T[h][i][j])+0.0;
                        System.out.print(value+" ");
                    }
                    System.out.println();
                }
                System.out.println();
            }
        }
    }
}

